package net.wanho.zaixian.cms.controller;

import com.alibaba.fastjson.JSONObject;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSDownloadStream;
import com.mongodb.client.gridfs.model.GridFSFile;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import net.wanho.zaixian.cms.service.CmsPageService;
import net.wanho.zaixian.cms.service.CmsTemplateService;
import net.wanho.zaixian.pojo.cms.CmsPage;
import net.wanho.zaixian.pojo.cms.CmsTemplate;
import org.apache.commons.io.IOUtils;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.http.ResponseEntity;
import org.springframework.jms.core.JmsMessagingTemplate;
import org.springframework.messaging.MessagingException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.jms.Topic;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.Map;
import java.util.Optional;

@RestController
public class CmsPageController {
    @Resource
    private CmsPageService cmsPageService;

    @Resource
    private GridFsTemplate gridFsTemplate;
    @Resource
    private GridFSBucket gridFSBucket;

    @Resource
    private CmsTemplateService cmsTemplateService;

    @Resource
    private RestTemplate restTemplate;

    @Autowired
    private JmsMessagingTemplate jmsTemplate;

    @Resource
    private Topic topic;

    /**
     * 查询所有的页面
     *
     * @param page
     * @param size
     * @param siteId
     * @return
     */
    @GetMapping("/cms/page/list/{page}/{size}")
    public org.springframework.data.domain.Page listPage(@PathVariable("page") int page,
                                                         @PathVariable("size") int size,
                                                         @RequestParam(name = "siteId", required = false) String siteId) {
        return cmsPageService.listPage(page, size, siteId);
    }


    /**
     * 增加一个页面
     *
     * @param cmsPage
     * @return
     */
    @PostMapping("/cms/page/add")
    public JSONObject addPage(@RequestBody CmsPage cmsPage) {

        JSONObject jsonObject = new JSONObject();
        try {
            cmsPageService.addPage(cmsPage);
            jsonObject.put("success", true);
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
            jsonObject.put("success", false);
            return jsonObject;
        }
    }

    /**
     * 根据id查询页面
     */
    @GetMapping("/cms/page/get/{pageId}")
    public JSONObject getPage(@PathVariable String pageId) {
        JSONObject jsonObject = new JSONObject();
        Optional<CmsPage> byId = cmsPageService.getPage(pageId);
        CmsPage cmsPage = byId.get();
        if (cmsPage != null) {
            jsonObject.put("success", true);
            jsonObject.put("cmsPage", cmsPage);
            return jsonObject;
        }
        return null;
    }


    /**
     * 根据id修改页面
     *
     * @param pageId
     * @param cmsPage
     * @return
     */
    @PutMapping("/cms/page/edit/{pageId}")
    public JSONObject editPage(@PathVariable String pageId, @RequestBody CmsPage cmsPage) {

        JSONObject jsonObject = new JSONObject();
        try {
            cmsPageService.editPage(pageId, cmsPage);
            jsonObject.put("success", true);
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
            jsonObject.put("success", false);
            return jsonObject;
        }

    }

    /**
     * 删除page
     *
     * @param pageId
     * @return
     */
    @DeleteMapping("/cms/page/del/{pageId}")
    public JSONObject delPage(@PathVariable String pageId) {
        JSONObject jsonObject = new JSONObject();
        try {
            cmsPageService.delPage(pageId);
            jsonObject.put("success", true);
            return jsonObject;
        } catch (Exception e) {
            e.printStackTrace();
            jsonObject.put("success", false);
            return jsonObject;
        }
    }



    /**
     * 模板下载(这里仅仅将模板打印出来，而且模板文件的id是写死的)
     *
     * @return
     * @throws IOException
     */
    @RequestMapping("/gridfs/fetch")
    public String fetch() throws IOException {
        String fileId = "5f11740249960e1a200ce79d";//假设fs.files中有这样一个文件
        //根据id查询文件
        String s = getTemplateFileToString(fileId);
        System.out.println(s);

        return "ok";
    }


    /**
     * 生成静态页面
     *
     * @param cmsPageId
     * @return
     */
    @PostMapping("/cms/page/generateHtml/{cmsPageId}")

    public JSONObject generateHtml(@PathVariable(name = "cmsPageId") String cmsPageId) throws IOException {

        //根据page的id获取该page的模板文件id
        Optional<CmsPage> optional = cmsPageService.getPage(cmsPageId);
        CmsPage cmsPage = optional.get();
        String templateId = cmsPage.getTemplateId();
        CmsTemplate cmsTemplate = cmsTemplateService.getTemplateById(templateId);
        String templateFileId = cmsTemplate.getTemplateFileId();
        JSONObject jsonObject = new JSONObject();
        try {
            //根据模板文件的Id下载模板文件，并将内容转为字符串
            String templateFileContent = getTemplateFileToString(templateFileId);
            //获取dataUrl
            String dataUrl = cmsPage.getDataUrl();
            //获取与模板相对应的数据，以map的形式展现
            Map dataModel = getDataFromCmsPageDataUrl(dataUrl);
            //获取模板的真实路径
            String url = cmsPage.getPagePhysicalPath() + cmsPage.getPageName();
            Writer writer = new FileWriter(new File(url));
            combineTemplateAndData(writer, templateFileContent, dataModel);

            //静态化页面完成后，将生成的html页面上传到mongoDB中
            String htmlFileId = upLoadHtmlToMongoDB(url, cmsPage.getPageName());
            cmsPage.setHtmlFileId(htmlFileId);
            //将htmlFileId在cmsPage表中修改
            cmsPageService.editPage(cmsPageId,cmsPage);




            jsonObject.put("success", true);
            return jsonObject;
        } catch (TemplateException e) {
            e.printStackTrace();

            jsonObject.put("success", false);
            return jsonObject;
        }

    }


    /**
     * 页面预览
     *
     * @param cmsPageId
     * @return
     */
    @GetMapping("cms/page/preview/{cmsPageId}")
    public void perView(@PathVariable(value = "cmsPageId") String cmsPageId, HttpServletResponse response) throws IOException, TemplateException {
        //根据cmsPageId获取模板文件的Id
        Optional<CmsPage> optional = cmsPageService.getPage(cmsPageId);
        CmsPage cmsPage = optional.get();
        String templateId = cmsPage.getTemplateId();
        CmsTemplate cmsTemplate = cmsTemplateService.getTemplateById(templateId);
        String templateFileId = cmsTemplate.getTemplateFileId();
        //根据模板文件的Id下载模板文件，并将内容转为字符串
        String templateFileContent = getTemplateFileToString(templateFileId);
        //获取dataUrl
        String dataUrl = cmsPage.getDataUrl();
        //获取与模板相对应的数据，以map的形式展现
        Map dataModel = getDataFromCmsPageDataUrl(dataUrl);
        Writer writer = response.getWriter();
        combineTemplateAndData(writer, templateFileContent, dataModel);


    }

    /**
     * 页面发布
     * @param cmsPageId
     * @return
     */
    @PostMapping("/cms/page/postPage/{cmsPageId}")
    public JSONObject doPost(@PathVariable(name ="cmsPageId") String cmsPageId){
        JSONObject jsonObject = new JSONObject();
        try {
            jmsTemplate.convertAndSend( topic, cmsPageId);
            jsonObject.put("success",true);
            return  jsonObject;
        } catch (MessagingException e) {
            e.printStackTrace();
            jsonObject.put("success",false);
            return jsonObject;
        }

    }

    /**
     * 根据模板文件的Id下载模板文件，并将内容转为字符串
     *
     * @param templateFileId
     * @return
     * @throws IOException
     */
    private String getTemplateFileToString(String templateFileId) throws IOException {
        //根据id查询文件
        GridFSFile gridFSFile =
                gridFsTemplate.findOne(Query.query(Criteria.where("_id").is(templateFileId)));
        //打开下载流对象
        GridFSDownloadStream gridFSDownloadStream =
                gridFSBucket.openDownloadStream(gridFSFile.getObjectId());
        //创建gridFsResource，用于获取流对象
        GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
        //获取流中的数据
        //        System.out.println(s);
        return IOUtils.toString(gridFsResource.getInputStream(), "UTF-8");
    }

    /**
     * 获取与模板相对应的数据，以map的形式展现
     *
     * @param dataUrl
     * @return
     */
    private Map getDataFromCmsPageDataUrl(String dataUrl) {

        //restTemplate中封装了OkHttp3ClientHttpRequestFactory
        ResponseEntity<Map> responseEntity = restTemplate.getForEntity(dataUrl, Map.class);
        //获取请求的响应体（也就是准备与模板整合的数据）
        return responseEntity.getBody();
    }

    /**
     * 整合数据和模板
     *
     * @param writer
     * @param templateFileContent
     * @param dataModel
     * @throws IOException
     * @throws TemplateException
     */

    private void combineTemplateAndData(Writer writer, String templateFileContent, Map dataModel) throws IOException, TemplateException {
        //根据GridFS获取到的模板的流数据配置成模板
        Template template = new Template("template", new StringReader(templateFileContent), new Configuration(Configuration.VERSION_2_3_23));
        //模板与其将要整合的数据，进行整合，输出入境为前面获取的物理路径
        template.process(dataModel, writer);
    }

    /**
     * 根据静态化网页存在的路径和网页的名称，将网页上传到mongoDB，返回文件上传后的id；
     * @param url
     * @param htmlName
     * @return
     * @throws FileNotFoundException
     */
    public String upLoadHtmlToMongoDB(String url,String htmlName) throws FileNotFoundException {
        InputStream is = new FileInputStream(new File(url));
        //向GridFS存储文件
        ObjectId objectId = gridFsTemplate.store(is, htmlName, "text");
        String htmlFileId = objectId.toString();
        return htmlFileId;

    }
}

